package org.hcf.api.controller;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import lombok.extern.slf4j.Slf4j;
import org.hcf.api.base.Const;
import org.hcf.api.base.ErrorCode;
import org.hcf.api.base.Helper;
import org.hcf.api.base.SnowflakeUtils;
import org.hcf.api.tencent.api.FriendGetReq;
import org.hcf.api.tencent.callback.info.group.base.MessageBody;
import org.hcf.api.tencent.callback.info.content.IMAGE;
import org.hcf.api.tencent.callback.info.content.TEXT;
import org.hcf.api.tencent.callback.info.group.base.ImageInfo;
import org.hcf.api.tencent.api.FriendChatMsg;
import org.hcf.api.tencent.api.GroupChatMsg;
import org.hcf.api.http.PluginChatReq;
import org.hcf.data.RedisUtils;
import org.hcf.data.cache.CacheConfig;
import org.hcf.data.cache.Caches;
import org.hcf.data.entity.ChatGroup;
import org.hcf.data.entity.ChatUser;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.*;
import org.tio.utils.hutool.StrUtil;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Order(99)
@RestController
@RequestMapping("/plugin")
public class PluginController {
    static final String AUTH_INFO = "SESSION_ID";
    private static final int QR_CODE_SIZE = 200;
    String secret = "f2708c8fe04ed10a032f1aafcb17bd256c7e9940da4115cf8ba84bd21e9e7c64";
    AtomicLong msgId = new AtomicLong(RandomUtil.randomInt());
    AtomicLong random = new AtomicLong(RandomUtil.randomInt());
    String QRCODE = "MATRIX_QRCODE_ID";

    /** 登录 */
    @CrossOrigin(origins = "*")
    @PostMapping(value = "/login")
    public JSONObject login(@RequestBody String str, HttpServletRequest httpRequest) {
//        AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, secret.getBytes(), Arrays.copyOfRange(secret.getBytes(), 0, 16));
        JSONObject request = JSONObject.parseObject(str);
        String time = request.getString("time");
        String code = request.getString("code");
        if (StrUtil.isBlank(time) || StrUtil.isBlank(code)) {
            return toResponse(ErrorCode.PARAM_ERROR);
        }
        String md5 = SecureUtil.md5(secret + time);
        if (md5.equalsIgnoreCase(code)) {
            String token = String.valueOf(SnowflakeUtils.nextId());
            Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).put(token, true);
            JSONObject json = new JSONObject();
            json.put("sessionId", token);
            return toResponse(json);
        }
        return toResponse(ErrorCode.TOKEN_ERROR);
    }


    @CrossOrigin(origins = "*")
    @PostMapping("/getIPadLogin")
    public JSONObject getIPadLogin(@RequestHeader(AUTH_INFO) String session) {
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(session, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
        try {
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            String code = UUID.randomUUID(true).toString();//UUID.randomUUID().toString();
            String imageName = SnowflakeUtils.nextId() + ".png";
            String filePath = Helper.RES.getDir() + "/matrix/" + imageName;
            String imageUrl = Helper.RES.getUrl() + "/matrix/" + imageName;
            JSONObject matrixInfo = new JSONObject();
            long time = System.currentTimeMillis();
            String url = Helper.LocalURL + "/plugin/bindPlugin";
            matrixInfo.put("qrCodeId", code);
            matrixInfo.put("url", url);
            matrixInfo.put("type", QRCODE);
            matrixInfo.put("time", time);
//            log.error("二维码信息:" + matrixInfo);
//            System.out.println("二维码信息:" + matrixInfo);
            BitMatrix bitMatrix = qrCodeWriter.encode(matrixInfo.toJSONString(), BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE);
//            if (!isHasMatrixPath()) FileUtil.mkParentDirs(filePath);
            MatrixToImageWriter.writeToFile(bitMatrix, "PNG", new File(filePath));
            Caches.getCache(CacheConfig.PLUGIN_LOGIN_QR).put(code, true);
            JSONObject data = new JSONObject();
            data.put("qrCodeId", code);
            data.put("qrCodeUrl", imageUrl);
            return toResponse(data);
        } catch (Throwable ex) {
            log.error("生成二维码异常!!!", ex);
            return toResponse(ErrorCode.MATRIX_GENERATE_FAIL);
        }
    }

    /** 检查二维码是否登录成功 */
    @CrossOrigin(origins = "*")
    @PostMapping("/getIPadLoginInfo")
    public JSONObject getIPadLoginInfo(@RequestHeader(AUTH_INFO) String session, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        String qrCodeId = request.getString("qrCodeId");
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(session, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
        if (StrUtil.isBlank(qrCodeId)) return toResponse(ErrorCode.PARAM_ERROR);
        Long userId = Caches.getCache(CacheConfig.PLUGIN_QR_USER).get(qrCodeId, Long.class);
        if (userId == null) return toResponse(ErrorCode.MATRIX_NOT_USE);
        ChatUser user = RedisUtils.getUser(userId);
        if (user == null) return toResponse(ErrorCode.USER_NOT_EXIST);
        JSONObject json = new JSONObject();
        json.put("accid", userId);
        json.put("headImgUrl", user.getAvatar());
        json.put("mobilePhone", user.getPhone());
        json.put("nickName", user.getNickName());
        json.put("qrCodeId", qrCodeId);
//        try {
//            RequestExt ext = WebUtils.getRequestExt(request);
//            ext.setDeviceType(Devicetype.H5.getValue());
//            HttpResponse rsp = LoginController.login(request, user, false);
//            System.out.println("plugin用户[" + user.getId() + "]登录完成:" + rsp.getBodyString());
//        } catch (Throwable ex) {
//            System.err.println("plugin用户[" + user.getId() + "]登录异常!!!");
//        }
        return toResponse(json);
    }

    /** 获取联系人信息 */
    @CrossOrigin(origins = "*")
    @PostMapping("/getContact")
    public JSONObject getContact(@RequestHeader(AUTH_INFO) String session, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        long accid = request.getLong("accid");
//        log.info("接收客户端http请求:" + request);
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(session, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
//        Long clientId = RedisUtils.getTokenClientMap().get(token);
//        if (clientId == null) return toResponse(request,ErrorCode.TOKEN_ERROR);
        if (accid <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        try {
            long userId = accid;
            ChatUser user = RedisUtils.getUser(userId);
            if (user == null) return toResponse(ErrorCode.USER_NOT_EXIST);

            JSONObject json = new JSONObject();
            json.put("accid", userId);
            json.put("headImgUrl", user.getAvatar());
            json.put("mobilePhone", user.getPhone());
            json.put("nickName", user.getNickName());
            return toResponse(json);
        } catch (Throwable ex) {
            log.error("获取联系人信息异常!!!", ex);
            return toResponse(ErrorCode.PARAM_ERROR);
        }
    }

    /** 获取好友信息 */
    @CrossOrigin(origins = "*")
    @PostMapping("/getFriendContact")
    public JSONObject getFriendContact(@RequestHeader(AUTH_INFO) String session, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        long accid = request.getLong("accid");
        String faccid = request.getString("faccid");
//        log.info("接收客户端http请求:" + request);
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(session, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
//        Long clientId = RedisUtils.getTokenClientMap().get(token);
//        if (clientId == null) return toResponse(request,ErrorCode.TOKEN_ERROR);
        if (accid <= 0 || StrUtil.isBlank(faccid)) return toResponse(ErrorCode.PARAM_ERROR);
        try {
            int friendUId;
            try {
                friendUId = Integer.parseInt(faccid);
                if (friendUId <= 0) return toResponse(ErrorCode.PARAM_ERROR);
            } catch (Throwable ex) {
                return toResponse(ErrorCode.PARAM_ERROR);
            }
            long userId = accid;
            if (userId == 0) toResponse(ErrorCode.PARAM_ERROR);

//            Long chatlinkid = null;
//            WxChatUserItem item = ChatIndexService.fdUserIndex(userId, friendUId);
//            if (item != null) chatlinkid = item.getChatlinkid();
//            if (chatlinkid == null) return toResponse(ErrorCode.IS_NOT_FRIEND, "对方不是你的好友");

            ChatUser user = RedisUtils.getUser(friendUId);
            if (user == null) return toResponse(ErrorCode.USER_NOT_EXIST);

            JSONObject json = new JSONObject();
            json.put("accid", userId);
            json.put("headImgUrl", user.getAvatar());
            json.put("mobilePhone", user.getPhone());
            json.put("nickName", user.getNickName());
            return toResponse(json);
        } catch (Throwable ex) {
            log.error("获取联系人信息异常!!!", ex);
            return toResponse(ErrorCode.PARAM_ERROR);
        }
    }

    /** 获取用户在线状态 */
    @CrossOrigin(origins = "*")
    @PostMapping("/getStatus")
    public JSONObject getStatus(@RequestHeader(AUTH_INFO) String session, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        long accid = request.getLong("accid");
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(session, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
        if (accid <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        try {
            long userId = accid;
            ChatUser user = RedisUtils.getUser(userId);
            if (user == null) return toResponse(ErrorCode.USER_NOT_EXIST);
            String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(String.valueOf(userId), String.class);
//            if (qrCodeId == null) return toResponse(request, ErrorCode.MATRIX_NOT_USE);
            JSONObject json = new JSONObject();
            json.put("accid", userId);
            json.put("ipadOnline", StrUtil.isNotBlank(qrCodeId));
            return toResponse(json);
        } catch (Throwable ex) {
            return toResponse(ErrorCode.PARAM_ERROR);
        }
    }

    /** 获取所有授权用户 */
    @CrossOrigin(origins = "*")
    @PostMapping("/getBindUsers")
    public JSONObject getBindUsers() {
        Iterable<String> ks = Caches.getCache(CacheConfig.PLUGIN_USER_QR).keys();
        List<String> keys = new ArrayList<>();
        for (String k : ks) {
            keys.add(k);
        }
        JSONObject json = new JSONObject();
        json.put("users", keys);
        return toResponse(json);
    }

    /** 唤醒 */
    @CrossOrigin(origins = "*")
    @PostMapping("/awaken")
    public JSONObject awaken(@RequestHeader(AUTH_INFO) String session, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        long accid = request.getLong("accid");
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(session, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
        long userId = accid;
        if (userId <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        ChatUser user = RedisUtils.getUser(userId);
        if (user == null) return toResponse(ErrorCode.USER_NOT_EXIST);
        String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(String.valueOf(userId), String.class);
        if (StrUtil.isNotBlank(qrCodeId)) return toResponse(ErrorCode.IS_BIND_PLUGIN);
        qrCodeId = UUID.randomUUID(true).toString();

        Caches.getCache(CacheConfig.PLUGIN_QR_USER).put(qrCodeId, userId);
        Caches.getCache(CacheConfig.PLUGIN_USER_QR).put(String.valueOf(userId), qrCodeId);
        System.out.println("====================== 唤醒 绑定玩家[" + userId + "]与[" + qrCodeId + "]  ====================");
        Caches.getCache(CacheConfig.PLUGIN_LOGIN_QR).remove(qrCodeId);
        RedisUtils.initGA2UID(userId);
        RedisUtils.initPluginUser(userId);

//        WxChatApi.sendPluginOnline(userId, true);

        JSONObject json = new JSONObject();
        json.put("accid", userId);
        json.put("headImgUrl", user.getAvatar());
        json.put("mobilePhone", user.getPhone());
        json.put("nickName", user.getNickName());
        json.put("qrCodeId", qrCodeId);

        return toResponse(json);
    }

    /** 登录退出 */
    @CrossOrigin(origins = "*")
    @PostMapping("/logout")
    public JSONObject logout(@RequestHeader(AUTH_INFO) String session, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        log.info("收到plugin.logout 请求:" + str + " , session:" + session);
        long accid = request.getLong("accid");
        if (accid <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(session, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
        try {
            long userId = accid;
            if (userId == 0) return toResponse(ErrorCode.PARAM_ERROR);
            JSONObject json = new JSONObject();
            json.put("accid", userId);
            String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(String.valueOf(userId), String.class);
            if (qrCodeId == null) return toResponse(json);
            ChatUser user = RedisUtils.getUser(userId);
            if (user == null) return toResponse(ErrorCode.USER_NOT_EXIST);
            Caches.getCache(CacheConfig.PLUGIN_USER_QR).remove(String.valueOf(userId));
            Caches.getCache(CacheConfig.PLUGIN_QR_USER).remove(qrCodeId);
            RedisUtils.removeGA2UID(userId);
//            Caches.getCache(CacheConfig.PLUGIN_USER_GROUP).remove(String.valueOf(userId));
            log.info("====================== plugin主动退出 解绑玩家[" + userId + "]与[" + qrCodeId + "]  ====================");
            Helper.sendOfflineToPlugin(userId);
            return toResponse(json);
        } catch (Throwable ex) {
            return toResponse(ErrorCode.PARAM_ERROR);
        }
    }

    /** 登录退出 */
    @CrossOrigin(origins = "*")
    @PostMapping("/friendGet")
    public JSONObject friendGet(@RequestHeader(AUTH_INFO) String session, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        long accid = request.getLong("accid");
        if (accid <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        String url = Helper.getAPI(Const.API.FRIEND_GET);
        FriendGetReq req = new FriendGetReq();
        req.setFrom_Account(String.valueOf(accid));
//        req.setStartIndex(0);
//        req.setStandardSequence(0);
        String data = HttpUtil.post(url, JSONObject.toJSONString(req));
        return JSONObject.parseObject(data);
    }

    /** 用户授权 */
    @CrossOrigin(origins = "*")
    @PostMapping(value = "/bindPlugin")
    public JSONObject bindPlugin(@RequestBody JSONObject json) {
        Long userId = json.getLong("userId");
        Long session = json.getLong("session");
        String code = json.getString("qrCodeId");
        if (userId == null || userId <= 0 || session == null || session <= 0 || StrUtil.isBlank(code))
            return toResponse(ErrorCode.PARAM_ERROR);
        Long auth = Caches.getCache(CacheConfig.USER_LOGIN_TOKEN).get(userId.toString(), Long.class);
        if (auth == null || !auth.equals(session)) {
            log.info("用户[" + userId + "]授权请求,身份验证[" + session + "==" + auth + "]失败!!!");
            return toResponse(ErrorCode.TOKEN_ERROR);
        }
        String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(userId.toString(), String.class);
        if (StrUtil.isNotBlank(qrCodeId)) return toResponse(ErrorCode.IS_BIND_PLUGIN);
        Boolean hasQR = Caches.getCache(CacheConfig.PLUGIN_LOGIN_QR).get(code, Boolean.class);
        if (hasQR == null || !hasQR) return toResponse(ErrorCode.MATRIX_TIME_OUT);
        qrCodeId = code;
        Caches.getCache(CacheConfig.PLUGIN_QR_USER).put(qrCodeId, userId);
        Caches.getCache(CacheConfig.PLUGIN_USER_QR).put(userId.toString(), qrCodeId);
        log.info("======================  绑定玩家[" + userId + "]与[" + code + "]  ====================");
        Caches.getCache(CacheConfig.PLUGIN_LOGIN_QR).remove(qrCodeId);
        Helper.sendOfflineToPlugin(userId);
//        Helper.createPluginUserGroup(userId);
        RedisUtils.initGA2UID(userId);
        RedisUtils.initPluginUser(userId);
//        Set<Long> gs = Helper.createPluginUserGroup(userId);
//        if (gs != null && gs.size() > 0) RedisUtils.getGroups(gs.toArray(new Long[0]));
        return toResponse(ErrorCode.SUCCESS);
    }

    /** 取消授权 */
    @CrossOrigin(origins = "*")
    @PostMapping(value = "/unbindPlugin")
    public JSONObject unbindPlugin(@RequestBody JSONObject json) {
        Long userId = json.getLong("userId");
        Long session = json.getLong("session");
        if (userId == null || userId <= 0 || session == null || session <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        Long auth = Caches.getCache(CacheConfig.USER_LOGIN_TOKEN).get(userId.toString(), Long.class);
        if (auth == null || !auth.equals(session)) {
            log.info("用户[" + userId + "]取消授权,身份验证[" + session + "==" + auth + "]失败!!!");
            return toResponse(ErrorCode.TOKEN_ERROR);
        }

        String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(userId.toString(), String.class);
        if (StrUtil.isNotBlank(qrCodeId)) {
            Caches.getCache(CacheConfig.PLUGIN_USER_QR).remove(userId.toString());
            Caches.getCache(CacheConfig.PLUGIN_QR_USER).remove(qrCodeId);
            RedisUtils.removeGA2UID(userId);
//            Caches.getCache(CacheConfig.PLUGIN_USER_GROUP).remove(userId.toString());
            Helper.sendOfflineToPlugin(userId);
            log.info("======================  解绑玩家[" + userId + "]与[" + qrCodeId + "]  ====================");
        }
        return toResponse(ErrorCode.SUCCESS);
    }

    /** 用户是否在线 */
    @CrossOrigin(origins = "*")
    @PostMapping(value = "/isOnline")
    public JSONObject isOnline(@RequestBody JSONObject json) {
        Long userId = json.getLong("userId");
        Long session = json.getLong("session");
        if (userId == null || userId <= 0 || session == null || session <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        Long auth = Caches.getCache(CacheConfig.USER_LOGIN_TOKEN).get(userId.toString(), Long.class);
        if (auth == null || !auth.equals(session)) {
            log.info("用户[" + userId + "]获取在线状态,身份验证[" + session + "==" + auth + "]失败!!!");
            return toResponse(ErrorCode.TOKEN_ERROR);
        }
        String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(userId.toString(), String.class);
        JSONObject data = new JSONObject();
        data.put("isOnline", StrUtil.isNotBlank(qrCodeId));
        return toResponse(data);
    }


    String getRealChatType(int type) {
        if (type == 1) return Const.MSG_TYPE.TEXT;
        if (type == 2) return Const.MSG_TYPE.IMG;
        if (type == 3) return Const.MSG_TYPE.AUDIO;
        if (type == 4) return Const.MSG_TYPE.VIDEO;
        if (type == 5) return Const.MSG_TYPE.FILE;
        return null;
    }

    /** 获取用户session */
    @CrossOrigin(origins = "*")
    @PostMapping("/getUserSession")
    public JSONObject getUserSession(@RequestHeader(AUTH_INFO) String token, @RequestBody String str) {
        JSONObject request = JSONObject.parseObject(str);
        long accid = request.getLong("accid");
        if (accid <= 0) return toResponse(ErrorCode.PARAM_ERROR);
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(token, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);
        Long session = Caches.getCache(CacheConfig.USER_LOGIN_TOKEN).get(String.valueOf(accid), Long.class);
        if (session == null || session <= 0) return toResponse(ErrorCode.USER_NOT_LOGIN);
        JSONObject json = new JSONObject();
        json.put("session", session.toString());
        return toResponse(json);
    }

    /** 发送消息 */
    @CrossOrigin(origins = "*")
    @PostMapping("/sendText")
    public JSONObject sendText(@RequestHeader(AUTH_INFO) String token, @RequestBody String str) {
        log.info("收到pluginSendText:" + str);
//        @RequestParam("from") long from, @RequestParam("to") String to, @RequestParam("contentType") short contentType, @RequestParam("data") String data
        JSONObject request = JSONObject.parseObject(str);
        long from = request.getLong("from");
        String to = request.getString("to");
        short contentType = request.getShort("contentType");
        String data = request.getString("data");
        if (from <= 0 || StrUtil.isBlank(to) || contentType <= 0 || contentType > 5 || StrUtil.isBlank(data)) //chatType <= 0 || chatType > 2 ||
            return toResponse(ErrorCode.PARAM_ERROR);
//        ChatReq req = data.toJavaObject(ChatReq.class);
        PluginChatReq req = new PluginChatReq();
        req.from = from;
        int chatType;
        try {
            if (to.endsWith("@chatroom")) {
                String id = to.substring(0, to.length() - "@chatroom".length());
                req.to = Integer.parseInt(id);
                chatType = 2;
            } else {
                req.to = Integer.parseInt(to);
                chatType = 1;
            }
        } catch (Throwable ex) {
            return toResponse(ErrorCode.PARAM_ERROR);
        }
        req.contentType = contentType;
        req.data = data;
        String msgType = getRealChatType(req.contentType);
        if (StrUtil.isBlank(msgType)) toResponse(ErrorCode.PARAM_ERROR);
        Boolean isPluginLogin = Caches.getCache(CacheConfig.PLUGIN_LOGIN_TOKEN).get(token, Boolean.class);
        if (isPluginLogin == null || !isPluginLogin) return toResponse(ErrorCode.TOKEN_ERROR);

        String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(String.valueOf(req.getFrom()), String.class);
        if (StrUtil.isBlank(qrCodeId)) return toResponse(ErrorCode.SENDER_MUST_IS_MATRIX);
        long userId = req.getFrom();
        ChatUser user = RedisUtils.getUser(userId);
        if (user == null) return toResponse(ErrorCode.SENDER_NOT_EXIST);
        req.data = getFileData(req, msgType, chatType);
        return sendMsg(chatType, req.data);
    }

    String getFileData(PluginChatReq req, String msgType, int chatType) {
        SerializeConfig config = new SerializeConfig();
        config.propertyNamingStrategy = PropertyNamingStrategy.PascalCase;

        MessageBody body = new MessageBody();
        if (StrUtil.equalsIgnoreCase(msgType, Const.MSG_TYPE.IMG)) {
            JSONObject json = JSONObject.parseObject(req.getData());
            String md5 = json.getString("Md5");
            ImageInfo info = json.toJavaObject(ImageInfo.class);
            info.setType(1);
            String suffix = info.getURL().substring(info.getURL().lastIndexOf(".") + 1, info.getURL().length());

            IMAGE img = new IMAGE();
            img.setUUID(md5);
            img.setImageFormat(getImageFormat(suffix != null ? suffix.trim().toUpperCase() : null));
            img.setImageInfoArray(Arrays.asList(info, info.copy(2), info.copy(3)));
            body.setMsgType(msgType);
            body.setMsgContent(img);
//            return Json.toJson(img);
        } else if (StrUtil.equalsIgnoreCase(msgType, Const.MSG_TYPE.TEXT)) {
            TEXT text = new TEXT();
            text.setText(req.getData());
            body.setMsgType(msgType);
            body.setMsgContent(text);
        } else {
            body.setMsgType(msgType);
            body.setMsgContent(JSONObject.parseObject(req.getData()));
        }
        if (chatType == 1) {
            FriendChatMsg msg = new FriendChatMsg();
            msg.setFrom_Account(String.valueOf(req.getFrom()));
            msg.setTo_Account(String.valueOf(req.getTo()));
            msg.setMsgSeq((int) (SnowflakeUtils.nextId() & Integer.MAX_VALUE));
            msg.setMsgRandom((int) (random.incrementAndGet() & Integer.MAX_VALUE));
            msg.setMsgBody(Arrays.asList(body));
            return JSONObject.toJSONString(msg, config);
        } else if (chatType == 2) {
            GroupChatMsg msg = new GroupChatMsg();
            ChatGroup group = RedisUtils.getGroup(req.getTo());
            msg.setRandom((int) (SnowflakeUtils.nextId() & Integer.MAX_VALUE));
            msg.setFrom_Account(String.valueOf(req.getFrom()));
            msg.setGroupId(group.getGroupAccount());
            msg.setMsgBody(Arrays.asList(body));
            return JSONObject.toJSONString(msg, config);
        }
        return req.getData();
    }

    short getImageFormat(String suffix) {
        if (StrUtil.equalsIgnoreCase(suffix, "jpg")) return 1;
        else if (StrUtil.equalsIgnoreCase(suffix, "gif")) return 2;
        else if (StrUtil.equalsIgnoreCase(suffix, "png")) return 3;
        else if (StrUtil.equalsIgnoreCase(suffix, "bmp")) return 4;
        return 255;
    }

    JSONObject sendMsg(int chatType, String data) {
        String url = chatType == 1 ? Helper.getAPI(Const.API.FRIEND_SEND_MSG) : Helper.getAPI(Const.API.GROUP_SEND_MSG);
        try {
            String text = HttpUtil.post(url, data);
            JSONObject json = JSONObject.parseObject(text);
            int code = json.getInteger(Const.RES_FIELD.CODE);
            if (code == 0) {
                log.error("发送消息[" + data + "]到腾讯云成功");
                return toResponse(ErrorCode.SUCCESS);
            } else {
                log.error("发送消息[" + data + "]到腾讯云错误:" + text);
                return toResponse(code, json.getString(Const.RES_FIELD.MSG));
            }
        } catch (Throwable ex) {
            log.error("发送消息[" + data + "]到腾讯云异常!!", ex);
            return toResponse(ErrorCode.SEND_ERROR);
        }
    }

    static JSONObject toResponse(JSONObject json) {
        return toResponse(ErrorCode.SUCCESS, json);
    }

    static JSONObject toResponse(ErrorCode code) {
        return toResponse(code.NUM, code.DIC);
    }

    static JSONObject toResponse(ErrorCode code, JSONObject data) {
        JSONObject json = new JSONObject();
        json.put("code", code.NUM);
        json.put("msg", code.DIC);
        if (data != null) json.put("data", data);
        log.info("返回RESPONSE:" + json);
        return json;
    }

    static JSONObject toResponse(ErrorCode code, String msg) {
        return toResponse(code.NUM, msg);
    }

    static JSONObject toResponse(int code, String msg) {
        JSONObject json = new JSONObject();
        json.put("code", code);
        json.put("msg", msg);
        log.info("返回RESPONSE:" + json);
        return json;
    }
}
